package cn.bbstone.e4.ui.log;

import java.io.IOException;
import java.net.URL;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.encoder.LayoutWrappingEncoder;
import ch.qos.logback.core.joran.spi.JoranException;
import cn.bbstone.e4.ui.log.appender.E4LogbackAppender;

public class Activator implements BundleActivator {
	
	private static BundleContext context;
	
	/** Bundle in BundleContext of most recent start() call */
	private static Bundle bundle;

	static BundleContext getContext() {
		return context;
	}


	@Override
	public void start(BundleContext bundleContext) throws Exception {
		setContext(bundleContext);
		setBundle(bundleContext.getBundle());

		// set logger for Eclipse RCP IDE
		LoggerContext loggerContext = configureLogbackInBundle(bundleContext.getBundle());
		

		// ***** NOTICE: ******
		// class loader(which load logback.xml) of bundle(Bundle-SymbolicName:
		// ch.qos.logback.core) cannot load class in
		// bundle(Bundle-SymbolicName: cn.bbstone.e4.ui.log) class
		// cn.bbstone.e4.ui.log.appender.E4LogbackAppender,
		// because the two bundle has different class loader, refer:
		// https://www.vogella.com/tutorials/OSGi/article.html#specifying-the-api-of-a-plug-in-and-its-dependencies
		
		
		// set logger for Pi2 
		E4LogbackAppender<ILoggingEvent> e4Appender = new E4LogbackAppender<ILoggingEvent>();
		bundleContext.registerService(E4LogbackAppender.class, e4Appender, null);
		addCustomizeAppender(loggerContext, e4Appender);
	}

	@Override
	public void stop(BundleContext bundleContext) throws Exception {
		Activator.context = null;
	}

	/**
	 * Set bundle context singleton. Keeps Findbugs happy when set by method call
	 * from non-static class member.
	 * 
	 * @return BundleContext
	 */
	static void setContext(BundleContext bundleContext) {
		context = bundleContext;
	}

	/**
	 * Set bundle singleton. Keeps Findbugs happy when set by method call from
	 * non-static class member.
	 * 
	 * @return Bundle
	 */
	static void setBundle(Bundle value) {
		bundle = value;
	}

	static public Bundle getBundle() {
		return bundle;
	}

	private LoggerContext configureLogbackInBundle(Bundle bundle) throws JoranException, IOException {
		LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
		JoranConfigurator jc = new JoranConfigurator();
		jc.setContext(loggerContext);
		loggerContext.reset();

		// this assumes that the logback.xml file is in the root of the bundle.
		URL logbackConfigFileUrl = FileLocator.find(bundle, new Path("logback-logpart.xml"), null);

		// following doConfigure will used classLoader of bundle(ch.qos.logback.core),
		// so class not define in this bundle will not found
		jc.doConfigure(logbackConfigFileUrl.openStream());

		
		return loggerContext;
	}

	/** TODO: read logback configs(pattern) from custom properties file  */
	public static void addCustomizeAppender(LoggerContext context, E4LogbackAppender<ILoggingEvent> e4Appender) {
//		E4LogbackAppender<ILoggingEvent> e4Appender = new E4LogbackAppender<ILoggingEvent>();
		e4Appender.setContext(context);
		e4Appender.setName("appender-logview");
		LayoutWrappingEncoder<ILoggingEvent> encoder = new LayoutWrappingEncoder<ILoggingEvent>();
		encoder.setContext(context);

		PatternLayout layout = new PatternLayout();
		layout.setPattern("%d{HH:mm:ss.SSS} %-5level %msg%n");
//		layout.setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%line - %msg%n");
		
//      layout.setPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");
//      TTLLLayout layout = new TTLLLayout();

		layout.setContext(context);
		layout.start();
		encoder.setLayout(layout);

		e4Appender.setEncoder(encoder);
		
		// NOTICE: not start now, should start @LogPart, after set logService(get ouputStream and set) to this appender
		//e4Appender.start(); 
		
		Logger rootLogger = context.getLogger(Logger.ROOT_LOGGER_NAME);
		rootLogger.addAppender(e4Appender);
	}

	
	public static BundleContext getBundleContext() {
		return context;
	}

}
